/*Copyright (C) 2009 Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "Error.h"
#include "Network.h"
#include "TCP.h"
#include "dll.h"

#include <string.h>


CSLP_TCPSOCKET DLL_IMPEXP CSLP_InitTCPSocket()
{
	#ifdef WIN32
	InitWSA();
	#endif
	return socket(AF_INET, SOCK_STREAM, 0);
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Connect(CSLP_TCPSOCKET sock, unsigned long IP, unsigned short port)
{
	CSLP_NETWORK_ERROR retVal = NONE;
	SOCKADDR_IN sockIn;
	sockIn.sin_addr.s_addr = IP;
	sockIn.sin_family = AF_INET;
	sockIn.sin_port = htons(port);
	memset(sockIn.sin_zero, 0, 8);
	if (connect(sock, (SOCKADDR*)&sockIn, sizeof(sockIn)) != 0)
	{
		retVal = CSLP_GetLastNetworkError();
	}
	return retVal;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_SendString(CSLP_TCPSOCKET sock, const char* str)
{
	return CSLP_Send(sock, str, strlen(str) * sizeof(char) + 1);
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Send(CSLP_TCPSOCKET sock, const void* data, size_t len)
{
	CSLP_NETWORK_ERROR retVal = NONE;
	if (send(sock, data, len, MSG_NOSIGNAL) == -1)
	{
		retVal = CSLP_GetLastNetworkError();
	}
	return retVal;
}

CSLP_NETWORK_ERROR DLL_IMPEXP CSLP_Receive(CSLP_TCPSOCKET sock, void* data, size_t dataLen, size_t* bytesWrite)
{
	CSLP_NETWORK_ERROR retVal = NONE;
	int lenRcv = recv(sock, data, dataLen, 0);
	if (lenRcv == -1)
	{
		retVal = CSLP_GetLastNetworkError();
	}
	else
	{
		*bytesWrite = lenRcv;
	}
	return retVal;
}

int DLL_IMPEXP CSLP_Listen(CSLP_TCPSOCKET sock, unsigned short port)
{
	int retVal = 0;
	SOCKADDR_IN sockIn;
	sockIn.sin_addr.s_addr = htonl(INADDR_ANY);
	sockIn.sin_family = AF_INET;
	sockIn.sin_port = htons(port);
	memset(sockIn.sin_zero, 0, 8);

	if (bind(sock, (SOCKADDR*)&sockIn, sizeof(sockIn)) != 0)
	{
		retVal = -1;
	}
	else
	{
		if (listen(sock, 8) != 0)
		{
			retVal = -1;
		}
	}
	return retVal;
}

int DLL_IMPEXP CSLP_Accept(CSLP_TCPSOCKET serverSocket, CSLP_TCPSOCKET* clientSocket, unsigned long* clientIP, unsigned short* clientPort)
{
	int retVal = 0;
	SOCKADDR_IN sockIn;
	socklen_t sockInLen;
	*clientSocket = accept(serverSocket, (SOCKADDR*)&sockIn, &sockInLen);
	if (*clientSocket != CSLP_INVALID_SOCKET)
	{
		#ifdef WIN32
		InitWSA();
		#endif
		if (clientIP != NULL)
		{
			*clientIP = sockIn.sin_addr.s_addr;
		}
		if (clientPort != NULL)
		{
			*clientPort = htons(sockIn.sin_port);
		}
	}
	else
	{
		retVal = -1;
	}
	return retVal;
}

void DLL_IMPEXP CSLP_CloseTCPSocket(CSLP_TCPSOCKET sock)
{
	#ifdef WIN32
	if (closesocket((SOCKET)(sock)) == 0)
	{
		CloseWSA();
	}
	#else
	close((int)(sock));
	#endif
}

